package com.ljx.recruitment.interview.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ljx.recruitment.common.domain.vo.resp.PageResp;
import com.ljx.recruitment.common.enums.CommonStatusTypeEnum;
import com.ljx.recruitment.common.exception.ApiException;
import com.ljx.recruitment.interview.constant.JobConstant;
import com.ljx.recruitment.interview.domain.entity.*;
import com.ljx.recruitment.interview.domain.vo.req.JobPageReq;
import com.ljx.recruitment.interview.domain.vo.req.JobProcessSubmitReq;
import com.ljx.recruitment.interview.domain.vo.req.JobSubmitReq;
import com.ljx.recruitment.interview.domain.vo.resp.DashboardJobCategoryResp;
import com.ljx.recruitment.interview.domain.vo.resp.JobHomeShowResp;
import com.ljx.recruitment.interview.domain.vo.resp.JobProcessTreeResp;
import com.ljx.recruitment.interview.domain.vo.resp.JobResp;
import com.ljx.recruitment.interview.enums.*;
import com.ljx.recruitment.interview.event.JobSubmitEvent;
import com.ljx.recruitment.interview.mapper.JobMapper;
import com.ljx.recruitment.interview.service.*;
import com.ljx.recruitment.security.common.PermissionConstant;
import com.ljx.recruitment.security.util.UserUtil;
import com.ljx.recruitment.user.cache.UserCache;
import com.ljx.recruitment.user.domain.entity.Permission;
import com.ljx.recruitment.user.domain.vo.resp.UserResp;
import com.ljx.recruitment.user.service.UserService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @Author: LiJunXi
 * @Description:
 * @Date: 2024-11-01  23:46
 */
@Service
public class JobServiceImpl extends ServiceImpl<JobMapper, Job> implements JobService {

    @Autowired
    private JobMapper jobMapper;

    @Autowired
    private JobTypeService jobTypeService;

    @Autowired
    private JobLocationService jobLocationService;

    @Autowired
    private DeliverService deliverService;

    @Autowired
    private UserService userService;

    @Autowired
    private JobProcessService jobProcessService;

    @Autowired
    private ApplicationEventPublisher applicationEventPublisher;

    @Autowired
    private UserCache userCache;

    @Override
    public JobResp getInfo(Long JobId) {
        Job Job = jobMapper.selectById(JobId);
        if (Job.getStatus().equals(CommonStatusTypeEnum.BAN.getKey())) {
            return null;
        }
        JobResp jobResp = BeanUtil.copyProperties(Job, JobResp.class);
        fillJobUIParams(jobResp);

        return jobResp;
    }

    @Override
    public PageResp<JobResp> getPage(JobPageReq req) {
        LambdaQueryWrapper<Job> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(Job::getTenantId, UserUtil.tryToGetTenantId());
        lambdaQueryWrapper.eq(Job::getStatus, CommonStatusTypeEnum.NORMAL.getKey());
        if (StrUtil.isNotEmpty(req.getKey())) {
            lambdaQueryWrapper.like(Job::getName, req.getKey());
        }
        if (Objects.nonNull(req.getCategory())) {
            lambdaQueryWrapper.eq(Job::getCategory, req.getCategory());
        }
        if (CollectionUtil.isNotEmpty(req.getType())) {
            lambdaQueryWrapper.in(Job::getJobTypeId, req.getType());
        }
        if (CollectionUtil.isNotEmpty(req.getKind())) {
            lambdaQueryWrapper.in(Job::getKind, req.getKind());
        }
        // 职位地点搜索（只要符合一处工作地址就行）
        if (CollectionUtil.isNotEmpty(req.getLocation())) {
            List<String> locations = jobLocationService.listByIds(req.getLocation())
                    .stream()
                    .map(JobLocation::getName)
                    .collect(Collectors.toList());
            lambdaQueryWrapper.and(wrapper -> {
                for (int i = 0; i < locations.size(); i++) {
                    if (i != locations.size() - 1) {
                        wrapper.like(Job::getJobLocationDetails, locations.get(i)).or();
                    } else {
                        wrapper.like(Job::getJobLocationDetails, locations.get(i));
                    }
                }
            });
        }
        PageResp<Job> page = getJobPage(req, lambdaQueryWrapper);
        List<JobResp> list = BeanUtil.copyToList(page.getList(), JobResp.class);
        return PageResp.<JobResp>builder()
                .total(page.getTotal())
                .list(fillJobUIParamsBath(list))
                .build();
    }

    @Override
    public PageResp<Job> getPageByAdmin(JobPageReq req) {
        LambdaQueryWrapper<Job> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(Job::getTenantId, UserUtil.tryToGetTenantId());
        if (StrUtil.isNotEmpty(req.getKey())) {
            lambdaQueryWrapper.like(Job::getName, req.getKey());
        }
        if (UserUtil.checkIsTenantAdmin() || UserUtil.checkIsPlatformAdmin()) {
            if (Objects.nonNull(req.getStatus())) {
                lambdaQueryWrapper.eq(Job::getStatus, req.getKey());
            }
        } else {
            lambdaQueryWrapper.eq(Job::getStatus, CommonStatusTypeEnum.NORMAL.getKey());
        }
        if (Objects.nonNull(req.getYear())) {
            lambdaQueryWrapper.eq(Job::getYear, req.getYear());
        }
        return getJobPage(req, lambdaQueryWrapper);
    }

    @Override
    @Transactional
    public JobResp submit(JobSubmitReq req) {
        UserUtil.checkIsSameTenant();
        Job job;
        if (Objects.isNull(req.getId())) {
            checkSubmitParams(req);
            job = BeanUtil.copyProperties(req, Job.class);
            fillSubmitParams(job);
            jobMapper.insert(job);
            applicationEventPublisher.publishEvent(new JobSubmitEvent(job.getId(), this));
        } else {
            job = jobMapper.selectById(req.getId());
            BeanUtils.copyProperties(req, job);
            jobMapper.updateById(job);
        }
        return getInfo(job.getId());
    }

    private void fillSubmitParams(Job job) {
        job.setTenantId(UserUtil.tryToGetTenantId());
        job.setOc(JobConstant.DEFAULT_OC);
        job.setYear(new DateTime().year());
    }

    private void fillJobUIParams(JobResp jobResp) {
        jobResp.setCategoryDesc(JobCategoryEnum.getByKey(jobResp.getCategory()).getDesc());
        jobResp.setKindDesc(JobKindEnum.getByKey(jobResp.getKind()).getDesc());
        jobResp.setJobTypeDesc(jobTypeService.getById(jobResp.getJobTypeId()).getName());
        if (UserUtil.checkIsNotLogin()) {
            jobResp.setDeliverOpt(false);
            return;
        }
        Map<String, Permission> permissionMap = UserUtil.getUserInfo().getPermissions()
                .stream()
                .collect(Collectors.toMap(Permission::getName, Function.identity()));
        jobResp.setDeliverOpt(permissionMap.containsKey(PermissionConstant.USER_DELIVER));
    }


    private List<JobResp> fillJobUIParamsBath(List<JobResp> list) {
        if (CollectionUtil.isEmpty(list)) {
            return new ArrayList<>();
        }
        List<Long> ids = list.stream().map(JobResp::getJobTypeId).collect(Collectors.toList());
        Map<Long, JobType> jobTypeMap = jobTypeService.listByIds(ids).stream().collect(Collectors.toMap(JobType::getId, Function.identity()));
        return list.stream().map(item -> {
            item.setCategoryDesc(JobCategoryEnum.getByKey(item.getCategory()).getDesc());
            item.setKindDesc(JobKindEnum.getByKey(item.getKind()).getDesc());
            item.setJobTypeDesc(jobTypeMap.get(item.getJobTypeId()).getName());
            return item;
        }).collect(Collectors.toList());
    }

    public PageResp<Job> getJobPage(JobPageReq req, LambdaQueryWrapper<Job> lambdaQueryWrapper) {
        Page<Job> page = jobMapper.selectPage(new Page<>(req.getCurrPage(), req.getPageSize()), lambdaQueryWrapper);
        return PageResp.<Job>builder()
                .total(page.getTotal())
                .list(page.getRecords())
                .build();
    }

    private void checkSubmitParams(JobSubmitReq req) {
        if (StrUtil.isEmpty(req.getName()) || Objects.isNull(req.getJobTypeId()) || Objects.isNull(req.getCategory()) ||
                Objects.isNull(req.getKind()) || StrUtil.isEmpty(req.getSalary()) || StrUtil.isEmpty(req.getJobRequire()) ||
                StrUtil.isEmpty(req.getJobDuty()) || Objects.isNull(req.getHc()) || CollUtil.isEmpty(req.getJobLocationDetails())) {
            throw new ApiException("参数不能为空");
        }
    }

    @Override
    public List<Integer> getFilterYearList() {
        List<Integer> result = new ArrayList<>();
        Integer nowYear = new DateTime().year();
        result.add(nowYear - 1);
        result.add(nowYear);
        result.add(nowYear + 1);
        return result;
    }

    @Override
    public List<UserResp> getJobOfferList(Long jobId) {
        List<Long> useIds = deliverService.list(new LambdaQueryWrapper<Deliver>()
                        .eq(Deliver::getJobId, jobId)
                        .eq(Deliver::getStatus, CommonStatusTypeEnum.NORMAL.getKey())
                        .eq(Deliver::getDeliverStatus, DeliverStatusEnum.OVER.getKey()))
                .stream().map(Deliver::getUId)
                .collect(Collectors.toList());
        if (CollectionUtil.isEmpty(useIds)) {
            return new ArrayList<>();
        }
        return userCache.getBatch(useIds)
                .values()
                .stream()
                .map(item -> BeanUtil.copyProperties(item, UserResp.class))
                .collect(Collectors.toList());
    }

    @Override
    public List<JobProcessTreeResp> getJobProcessTreeList(Long jobId) {
        Map<Integer, List<JobProcess>> jobProcessMap = jobProcessService.list(new LambdaQueryWrapper<JobProcess>()
                        .eq(JobProcess::getJobId, jobId)
                        .eq(JobProcess::getStatus, CommonStatusTypeEnum.NORMAL.getKey()))
                .stream()
                .collect(Collectors.groupingBy(JobProcess::getProcessKey));
        return Arrays.stream(JobBaseProcessEnum.values())
                .filter(item -> !item.getKey().equals(JobBaseProcessEnum.OFFER.getKey()) && !item.getKey().equals(JobBaseProcessEnum.OVER.getKey()))
                .map(item -> {
                    JobProcessTreeResp resp = new JobProcessTreeResp();
                    resp.setKey(item.getKey());
                    resp.setValue(item.getValue());
                    resp.setChildList(jobProcessMap.get(item.getKey()));
                    return resp;
                }).collect(Collectors.toList());
    }

    @Override
    public void submitProcess(JobProcessSubmitReq req) {
        if (!JobProcessSubmitOpEnum.cache.containsKey(req.getOp())) {
            throw new ApiException("非法操作");
        }
        if (JobBaseProcessEnum.OFFER.getKey().equals(req.getJobProcessKey())) {
            throw new ApiException("非法操作");
        }
        int nowCount = jobProcessService.count(new LambdaQueryWrapper<JobProcess>()
                .eq(JobProcess::getJobId, req.getJobId())
                .eq(JobProcess::getProcessKey, req.getJobProcessKey())
                .eq(JobProcess::getStatus, CommonStatusTypeEnum.NORMAL.getKey()));
        int newCount = nowCount + req.getOp();
        if (newCount > nowCount) {
            jobProcessService.saveByReq(req, newCount);
        } else {
            jobProcessService.deleteByReq(req, nowCount);
        }

    }

    @Override
    public Integer getTenantJobCount(Long tenantId) {
        if (Objects.isNull(tenantId)) {
            throw new ApiException("租户ID为空");
        }
        return lambdaQuery()
                .eq(Job::getTenantId, tenantId)
                .eq(Job::getStatus, CommonStatusTypeEnum.NORMAL.getKey())
                .count();
    }

    @Override
    public List<DashboardJobCategoryResp> getTenantJobCategory(Long tenantId) {
        if (Objects.isNull(tenantId)) {
            throw new ApiException("租户ID为空");
        }
        Map<Long, String> jobTypeMap = jobTypeService.list().stream().collect(Collectors.toMap(JobType::getId, JobType::getName));
        return jobMapper.getTenantJobCategory(tenantId)
                .stream()
                .map(item -> {
                    item.setName(jobTypeMap.get(Long.parseLong(item.getName())));
                    return item;
                }).collect(Collectors.toList());
    }

    @Override
    public JobHomeShowResp getHomeJobShow() {
        Map<Integer, List<Job>> jobMap = jobMapper.selectList(new LambdaQueryWrapper<Job>()
                        .eq(Job::getTenantId, UserUtil.tryToGetTenantId())
                        .eq(Job::getStatus, CommonStatusTypeEnum.NORMAL.getKey()))
                .stream()
                .collect(Collectors.groupingBy(Job::getCategory));
        return new JobHomeShowResp(
                jobMap.get(JobCategoryEnum.CAMPUS.getKey()),
                jobMap.get(JobCategoryEnum.SOCIAL.getKey())
        );
    }
}